#include "VSBoneNode.h"
#include "VSGraphicInclude.h"
#include "VSStream.h"
using namespace VSEngine2;
IMPLEMENT_RTTI(VSBoneNode,VSNode)
BEGIN_ADD_PROPERTY(VSBoneNode,VSNode)
REGISTER_PROPERTY(m_OffSetMatrix,OffSetMatrix,VSProperty::F_SAVE_LOAD_CLONE)
REGISTER_PROPERTY(m_OriginMatrix,OriginMatrix,VSProperty::F_SAVE_LOAD_CLONE)
REGISTER_PROPERTY(m_bIsEffector,IsEffector,VSProperty::F_SAVE_LOAD_CLONE)
REGISTER_PROPERTY(m_TargetPosInWorld,TargetPosInWorld,VSProperty::F_SAVE_LOAD_CLONE)
REGISTER_PROPERTY(m_bAllowTranslation,AllowTranslation,VSProperty::F_SAVE_LOAD_CLONE)
REGISTER_PROPERTY(m_fMinTranslation,MinTranslation,VSProperty::F_SAVE_LOAD_CLONE)
REGISTER_PROPERTY(m_fMaxTranslation,MaxTranslation,VSProperty::F_SAVE_LOAD_CLONE)
REGISTER_PROPERTY(m_bAllowRotation,AllowRotation,VSProperty::F_SAVE_LOAD_CLONE)
REGISTER_PROPERTY(m_fMinRotation,MinRotation,VSProperty::F_SAVE_LOAD_CLONE)
REGISTER_PROPERTY(m_fMaxRotation,MaxRotation,VSProperty::F_SAVE_LOAD_CLONE)
REGISTER_PROPERTY(m_fIKWeight,IKWeight,VSProperty::F_SAVE_LOAD_CLONE)
REGISTER_PROPERTY(m_cName,Name,VSProperty::F_SAVE_LOAD_CLONE)
END_ADD_PROPERTY
IMPLEMENT_INITIAL_BEGIN(VSBoneNode)
IMPLEMENT_INITIAL_END
VSBoneNode::VSBoneNode()
{
	m_bIsEffector = false;
	m_bAllowTranslation.SetBufferNum(3);
	m_fMinTranslation.SetBufferNum(3);
	m_fMaxTranslation.SetBufferNum(3);
	m_bAllowRotation.SetBufferNum(3);
	m_fMinRotation.SetBufferNum(3);
	m_fMaxRotation.SetBufferNum(3);
	for (int i = 0; i < 3; i++)
	{
		m_bAllowTranslation[i] = false;
		m_fMinTranslation[i] = -VSMAX_REAL;
		m_fMaxTranslation[i] = VSMAX_REAL;
		m_bAllowRotation[i] = true;
		m_fMinRotation[i] = -VSPI;
		m_fMaxRotation[i] = VSPI;
	}
	m_fIKWeight = 1.0f;
}
VSBoneNode::~VSBoneNode()
{

}
unsigned int VSBoneNode::DiskUse()const
{
	unsigned int Used = VSNode::DiskUse();
	Used += sizeof(VSMatrix3X3W) * 2;
	Used += sizeof(bool);
	Used += sizeof(VSVector3);

	Used += sizeof(bool) * 6;
	Used += sizeof(VSREAL) * 13;

	Used += m_cName.DiskUse();
	return Used;
}
bool VSBoneNode::Save(VSStream & rStream,unsigned int &iSaveUse)const
{
	if(!VSNode::Save(rStream,iSaveUse))
		return 0;
	if(!rStream.Write(&m_OffSetMatrix,sizeof(VSMatrix3X3W)))
		return 0;
	iSaveUse += sizeof(VSMatrix3X3W);

	if(!rStream.Write(&m_OriginMatrix,sizeof(VSMatrix3X3W)))
		return 0;
	iSaveUse += sizeof(VSMatrix3X3W);

	if(!rStream.Write(&m_bIsEffector,sizeof(bool)))
		return 0;
	iSaveUse += sizeof(bool);

	if(!rStream.Write(&m_TargetPosInWorld,sizeof(VSVector3)))
		return 0;
	iSaveUse += sizeof(VSVector3);

	if(!rStream.Write(m_bAllowTranslation.GetBuffer(),sizeof(bool) * 3))
		return 0;
	iSaveUse += sizeof(bool) * 3;

	if(!rStream.Write(m_fMinTranslation.GetBuffer(),sizeof(VSREAL) * 3))
		return 0;
	iSaveUse += sizeof(VSREAL) * 3;

	if(!rStream.Write(m_fMaxTranslation.GetBuffer(),sizeof(VSREAL) * 3))
		return 0;
	iSaveUse += sizeof(VSREAL) * 3;

	if(!rStream.Write(m_bAllowRotation.GetBuffer(),sizeof(bool) * 3))
		return 0;
	iSaveUse += sizeof(bool) * 3;

	if(!rStream.Write(m_fMinRotation.GetBuffer(),sizeof(VSREAL) * 3))
		return 0;
	iSaveUse += sizeof(VSREAL) * 3;

	if(!rStream.Write(m_fMaxRotation.GetBuffer(),sizeof(VSREAL) * 3))
		return 0;
	iSaveUse += sizeof(VSREAL) * 3;

	if(!rStream.Write(&m_fIKWeight,sizeof(VSREAL)))
		return 0;
	iSaveUse += sizeof(VSREAL);

	m_cName.Save(rStream,iSaveUse);
	return 1;
}
bool VSBoneNode::Load(VSStream & rStream,unsigned int &iSaveUse)
{
	if(!VSNode::Load(rStream,iSaveUse))
		return 0;
	if(!rStream.Read(&m_OffSetMatrix,sizeof(VSMatrix3X3W)))
		return 0;
	iSaveUse += sizeof(VSMatrix3X3W);


	if(!rStream.Read(&m_OriginMatrix,sizeof(VSMatrix3X3W)))
		return 0;
	iSaveUse += sizeof(VSMatrix3X3W);

	if(!rStream.Read(&m_bIsEffector,sizeof(bool)))
		return 0;
	iSaveUse += sizeof(bool);

	if(!rStream.Read(&m_TargetPosInWorld,sizeof(VSVector3)))
		return 0;
	iSaveUse += sizeof(VSVector3);


	if(!rStream.Read(m_bAllowTranslation.GetBuffer(),sizeof(bool) * 3))
		return 0;
	iSaveUse += sizeof(bool) * 3;

	if(!rStream.Read(m_fMinTranslation.GetBuffer(),sizeof(VSREAL) * 3))
		return 0;
	iSaveUse += sizeof(VSREAL) * 3;

	if(!rStream.Read(m_fMaxTranslation.GetBuffer(),sizeof(VSREAL) * 3))
		return 0;
	iSaveUse += sizeof(VSREAL) * 3;

	if(!rStream.Read(m_bAllowRotation.GetBuffer(),sizeof(bool) * 3))
		return 0;
	iSaveUse += sizeof(bool) * 3;

	if(!rStream.Read(m_fMinRotation.GetBuffer(),sizeof(VSREAL) * 3))
		return 0;
	iSaveUse += sizeof(VSREAL) * 3;

	if(!rStream.Read(m_fMaxRotation.GetBuffer(),sizeof(VSREAL) * 3))
		return 0;
	iSaveUse += sizeof(VSREAL) * 3;

	if(!rStream.Read(&m_fIKWeight,sizeof(VSREAL)))
		return 0;
	iSaveUse += sizeof(VSREAL);

	m_cName.Load(rStream,iSaveUse);
	return 1;
}
void VSBoneNode::ComputeNodeVisibleSet(VSCuller & Culler,bool bNoCull,double dAppTime)
{
	return;
}
bool VSBoneNode::Clone(const VSObject *pObject,unsigned int uiType)
{
	const VSBoneNode* Temp = DynamicCast<VSBoneNode>(pObject); 
	if(!Temp)
		return 0;
	if(VSNode::Clone(pObject,uiType))
	{
		m_OffSetMatrix = Temp->m_OffSetMatrix;
		m_OriginMatrix = Temp->m_OriginMatrix;
		m_bIsEffector = Temp->m_bIsEffector;
		m_TargetPosInWorld = Temp->m_TargetPosInWorld;
		m_cName = Temp->m_cName;
		for (unsigned int i = 0 ; i < 3 ; i++)
		{
			m_bAllowTranslation[i] = Temp->m_bAllowTranslation[i];
			m_fMinTranslation[i] = Temp->m_fMinTranslation[i];
			m_fMaxTranslation[i] = Temp->m_fMaxTranslation[i];

			m_bAllowRotation[i] = Temp->m_bAllowRotation[i];
			m_fMinRotation[i] = Temp->m_fMinRotation[i];
			m_fMaxRotation[i] = Temp->m_fMaxRotation[i];
		}

		m_fIKWeight = Temp->m_fIKWeight;
		return 1;
	}
	else
	{
		return 0;

	}
	
}
void VSBoneNode::CreateBoneOffSetAndOriginMatrix()
{
	if(m_pParent) 
	{
		m_World.Product(m_Local,m_pParent->GetWorldTransform());

	}
	else 
		m_World = m_Local; 


	m_OffSetMatrix = m_World.GetCombineInverse();
	m_OriginMatrix = m_Local.GetCombine();
	for (unsigned int i = 0; i < m_pChild.GetNum(); i++)	
	{ 
		if (m_pChild[i]) 
			if(m_pChild[i]->GetST() == VSSpatial::ST_BONE_NODE)
			{
				VSBoneNode * pBoneNode = StaticCast<VSBoneNode>(m_pChild[i]);
				pBoneNode->CreateBoneOffSetAndOriginMatrix(); 
				
			}
	} 


}
void VSBoneNode::GetIKMoveAxis(VSVector3 Axis[3])const
{
	if (m_pParent)
	{
		m_pParent->GetWorldRotate().GetUVN(Axis);
	}
	else
	{
		Axis[0] = VSVector3(1.0f,0.0f,0.0f);
		Axis[1] = VSVector3(0.0f,1.0f,0.0f);
		Axis[2] = VSVector3(0.0f,0.0f,1.0f);
	}

}
void VSBoneNode::ComputeIKLocalRotDelta(const VSMatrix3X3 & WorldRot,VSMatrix3X3 & LocalRotDelta)const
{
	if (m_pParent)
	{
		VSMatrix3X3 Inver;
		Inver.InverseOf(m_pParent->GetWorldRotate());
		LocalRotDelta = m_pParent->GetWorldRotate() * WorldRot * Inver;
	}
	else
	{
		LocalRotDelta = WorldRot;
	}

}
VSBoneNode * VSBoneNode::GetBoneNodeFromLevel(const VSUsedName & BoneName)
{
	VSBoneNode * pFind = NULL;
	if (m_cName == BoneName)
	{
		pFind = this;
	}
	else
	{
		for (unsigned int i = 0 ; i < m_pChild.GetNum() ; i++)
		{
			VSSpatial * pChild = m_pChild[i];
			pFind = ((VSBoneNode *)pChild)->GetBoneNodeFromLevel(BoneName);
			if (!pFind)
			{
				return pFind;
			}
		}
	}
	return pFind;
}
unsigned int VSBoneNode::GetAllBoneNum()const
{
	unsigned int uiLeafNum  = 1;
	for(unsigned int i = 0 ; i < m_pChild.GetNum() ; i++)
	{

		VSSpatial * pBone = m_pChild[i];
		uiLeafNum += ((VSBoneNode *)pBone)->GetAllBoneNum();


	}

	return uiLeafNum;
}
void VSBoneNode::GetAllBoneArray(VSArray<VSBoneNode *> & AllNodeArray)
{
	AllNodeArray.AddElement(this);
	for(unsigned int i = 0 ; i < m_pChild.GetNum() ; i++)
	{
		VSBoneNode * pBoneNode = DynamicCast<VSBoneNode>(m_pChild[i]);
		if (pBoneNode)
		{
			pBoneNode->GetAllBoneArray(AllNodeArray);
		}

		

	}
}